package com.sun.local.filter;

import cn.hutool.core.io.FileUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

import static com.sun.common.constants.Constant.SSQ_FILE_PATH;

/**
 * 根据出现次数多的指标生成数据
 */
public class FilterDataByTop {
    // Top数据路径
    public static final String READ_PATH = System.getProperty("user.dir") + File.separator + "data" +
            File.separator + "top" + File.separator + "ssq_top.text";
    // 生成数据路径
    public static final String WRITE_PATH = System.getProperty("user.dir") + File.separator + "data" +
            File.separator + "filter" + File.separator + "ssq_filter_top.text";
    // 随机数据路径
    public static final String WRITE_RANDOM_PATH = System.getProperty("user.dir") + File.separator + "data" +
            File.separator + "random" + File.separator + "ssq_filter_top_random.text";

    public static void main(String[] args) {
        // 读取文件数据
        List<String> ssqTopList = FileUtil.readUtf8Lines(READ_PATH);

        // 生成所有红球组合
        List<List<Integer>> combinations = getRedCombinations();

        // 过滤数据
        filterData(ssqTopList, combinations);

        // 写出数据
        waiteData(combinations,20, false);
    }

    /**
     * 过滤数据
     *
     * @param ssqTopList 排名数据
     * @param combinations 全部红球组合
     */
    private static void filterData(List<String> ssqTopList, List<List<Integer>> combinations) {
        // 过滤AC值
        filterAC(combinations, getCondition(ssqTopList,"AC"));

        // 过滤连号
        filterSerialNumber(combinations, getCondition(ssqTopList,"SerialNumber"));

        // 过滤和值
        filterSum(combinations, getConditionList(ssqTopList,"SUM"));

        // 过滤奇偶比
        filterOddEvenRatio(combinations, getCondition(ssqTopList,"OddEvenRatio"));

        // 过滤分布
        filterDistribution(combinations, getCondition(ssqTopList,"Distribution"));

        // 杀号
        filterKillNum(combinations,32, 33);

        // 过滤历史号码
        filterRepeat(combinations, FileUtil.readUtf8Lines(SSQ_FILE_PATH));
    }


    /**
     * 生成全量数据<br>
     * 生成1~33的所有数组
     *
     * @return 全量数据集合
     */
    public static List<List<Integer>> getRedCombinations() {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> combinations = new ArrayList<>();
        for (int i = 1; i < 29; i++) {
            for (int j = 2; j < 30; j++) {
                if (i >= j) {
                    continue;
                }
                for (int k = 3; k < 31; k++) {
                    if (j >= k) {
                        continue;
                    }
                    for (int l = 4; l < 32; l++) {
                        if (k >= l) {
                            continue;
                        }
                        for (int m = 5; m < 33; m++) {
                            if (l >= m) {
                                continue;
                            }
                            for (int n = 6; n < 34; n++) {
                                if (m >= n) {
                                    continue;
                                }
                                List<Integer> combination = new ArrayList<>();
                                combination.add(i);
                                combination.add(j);
                                combination.add(k);
                                combination.add(l);
                                combination.add(m);
                                combination.add(n);
                                combinations.add(combination);
//                                combinations.add(i + "," + j + "," + k + "," + l + "," + m + "," + n);
//                                for (int o = 1; o < 17; o++) {
//                                    combinations.add(i + "," + j + "," + k + "," + l + "," + m + "," + n + "+" + o);
//                                }
                            }
                        }
                    }
                }
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("所有组合可能性：" + combinations.size() + " 消耗时间：" + (endTime - startTime) + "ms");
        return combinations;
    }

    /**
     * 获取条件参数
     * @param ssqList 所有组合列表
     * @param type 类型
     * @return 条件参数
     */
    private static String getCondition(List<String> ssqList, String type) {
        Optional<String> first = ssqList.stream()
                .filter(line -> line.contains(type + "="))
                .map(line -> StringUtils.substringBetween(line, type + "=", ",").trim())
                .findFirst();
        return first.orElse("");
    }

    /**
     * 获取条件参数
     * @param ssqList 所有组合列表
     * @param type 类型
     * @return 条件参数
     */
    private static List<String> getConditionList(List<String> ssqList, String type) {
        return ssqList.stream()
                .filter(line -> line.contains(type + "="))
                .map(line -> StringUtils.substringBetween(line, type + "=", ",").trim())
                .collect(Collectors.toList());
    }

    /**
     * 过滤AC值<br>
     * 历史数据：8 > 7 > 6 > 9 > 10 > 5
     *
     * @param combinations 全部红球组合
     */
    public static void filterAC(List<List<Integer>> combinations, String acValue) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> acList = new ArrayList<>();
        combinations.forEach(combination -> {
            int calcACValue = calcACValue(combination);
            if(calcACValue == Integer.parseInt(acValue)) {
                acList.add(combination);
            }
        });
        combinations.clear();
        combinations.addAll(acList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉AC等于" + acValue + "后的所有组合数量：" + acList.size() + " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 计算AC值
     *
     * @param combinationList 单注组合
     * @return AC值
     */
    private static int calcACValue(List<Integer> combinationList) {
        int num1 = combinationList.get(0);
        int num2 = combinationList.get(1);
        int num3 = combinationList.get(2);
        int num4 = combinationList.get(3);
        int num5 = combinationList.get(4);
        int num6 = combinationList.get(5);

        Set<Integer> set = new HashSet<>();
        set.add(num6 - num1);
        set.add(num6 - num2);
        set.add(num6 - num3);
        set.add(num6 - num4);
        set.add(num6 - num5);

        set.add(num5 - num1);
        set.add(num5 - num2);
        set.add(num5 - num3);
        set.add(num5 - num4);

        set.add(num4 - num1);
        set.add(num4 - num2);
        set.add(num4 - num3);

        set.add(num3 - num1);
        set.add(num3 - num2);

        set.add(num2 - num1);

        // AC值公式：AC = R - (N - 1) -> N = 6
        return set.size() - (6 - 1);
    }

    /**
     * 过滤连号
     *
     * @param combinations 全部红球组合
     */
    private static void filterSerialNumber(List<List<Integer>> combinations, String serialNumber) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> serialNumberList = new ArrayList<>();
        combinations.forEach(combination -> {
            int calcSerialNumber = calcSerialNumber(combination);
            if(calcSerialNumber == Integer.parseInt(serialNumber)) {
                serialNumberList.add(combination);
            }
        });
        combinations.clear();
        combinations.addAll(serialNumberList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉连号" + serialNumber +"后的所有组合数量：" + serialNumberList.size() +
                " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 计算连号数
     */
    private static int calcSerialNumber(List<Integer> combinationList) {
        if(CollectionUtils.isEmpty(combinationList)) {
            return 0;
        }
        // 所有连号组合
        List<String> serialNumberList = new ArrayList<>();
        for (int i = 0; i < combinationList.size() - 1; i++) {
            String serialNumber = "";
            int front = combinationList.get(i);
            int after = combinationList.get(i + 1);
            if((front + 1) == after) {
                serialNumber = front + "-" + after;

                for (String s : serialNumberList) {
                    String[] split = s.split("-");
                    String smallNo = split[0];
                    String bigNo = split[split.length - 1];
                    if(StringUtils.equals(String.valueOf(front), bigNo)) {
                        serialNumber = smallNo + "-" + after;
                    }
                }
                serialNumberList.add(serialNumber);
            }
        }
        // 最大连号数量
        int maxCount = 0;
        for (String s : serialNumberList) {
            String[] split = s.split("-");
            int diff = Integer.parseInt(split[1]) - Integer.parseInt(split[0]) + 1;
            if(diff > maxCount) {
                maxCount = diff;
            }
        }
        return maxCount;
    }

    /**
     * 过滤和值
     * 历史排名：105 > 90 > 89 > 103 > 91 > 101 > 102 > 99 > 106 > 111 > 94
     *
     * @param combinations 全部红球组合
     */
    private static void filterSum(List<List<Integer>> combinations, List<String> sumList) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> sumCombinationList = new ArrayList<>();
        combinations.forEach(combination -> {
            int calcSum = combination.stream().mapToInt(Integer::intValue).sum();
            if(sumList.contains(String.valueOf(calcSum))) {
                sumCombinationList.add(combination);
            }
        });
        combinations.clear();
        combinations.addAll(sumCombinationList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉和值" + StringUtils.join(sumList, ",") + "后的所有组合数量：" +
                sumCombinationList.size() + " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 过滤奇偶比
     * 历史数据：3:3 > 4:2 > 2:4
     *
     * @param combinations 全部红球组合
     */
    private static void filterOddEvenRatio(List<List<Integer>> combinations, String oddEvenRatio) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> oddEvenRatioList = new ArrayList<>();
        combinations.forEach(combination -> {
            String calcOddEven = calcOddEven(combination);
            if(StringUtils.equals(calcOddEven, oddEvenRatio)) {
                oddEvenRatioList.add(combination);
            }
        });
        combinations.clear();
        combinations.addAll(oddEvenRatioList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉奇偶比" + oddEvenRatio + "后的所有组合数量：" + oddEvenRatioList.size() +
                " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 计算奇偶比
     */
    private static String calcOddEven(List<Integer> combinationList) {
        // 奇数的数量
        int oddNumbers = 0;
        // 偶数的数量
        int evenNumbers = 0;
        for (Integer integer : combinationList) {
            // 奇数
            if (integer % 2 != 0) {
                oddNumbers++;
            }
            // 偶数
            if (integer % 2 == 0) {
                evenNumbers++;
            }
        }
        return oddNumbers + ":" + evenNumbers;
    }

    /**
     * 过滤分布
     * 历史数据：2:2:2 > 3:1:2 > 3:1:2
     *
     * @param combinations 全部红球组合
     */
    private static void filterDistribution(List<List<Integer>> combinations, String distribution) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> distributionList = new ArrayList<>();
        combinations.forEach(combination -> {
            String calcDistribution = calcDistribution(combination);
            if(StringUtils.equals(calcDistribution, distribution)) {
                distributionList.add(combination);
            }
        });
        combinations.clear();
        combinations.addAll(distributionList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉分布" + distribution + "后的所有组合数量：" + distributionList.size() +
                " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 计算分布
     *
     */
    private static String calcDistribution(List<Integer> combinationList) {
        int count1 = 0;
        int count2 = 0;
        int count3 = 0;
        for (Integer value : combinationList) {
            if (value <= 11) {
                count1++;
            }
            if (value > 11 && value <= 22) {
                count2++;
            }
            if (value > 22 && value <= 33) {
                count3++;
            }
        }
        return count1 + ":" + count2 + ":" + count3;
    }

    /**
     * 排除号码
     *
     * @param combinations 全部红球组合
     * @param filterNum 过滤数字
     */
    private static void filterKillNum(List<List<Integer>> combinations, int... filterNum) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> filterNumList = combinations.stream()
                .filter(combination -> {
                    for (int num : filterNum) {
                        if (combination.contains(num)) {
                            return false;
                        }
                    }
                    return true;
                })
                .collect(Collectors.toList());
        combinations.clear();
        combinations.addAll(filterNumList);

        StringBuilder nums = new StringBuilder();
        for (int i = 0; i < filterNum.length; i++) {
            if(i != filterNum.length - 1) {
                nums.append(filterNum[i]).append(",");
            } else {
                nums.append(filterNum[i]);
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("过滤掉" + nums + "后的所有组合数量：" + filterNumList.size() +
                " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 过滤历史出现过的号码
     *
     * @param combinations 全部红球组合
     * @param historyNumList 历史号码
     */
    private static void filterRepeat(List<List<Integer>> combinations, List<String> historyNumList) {
        long startTime = System.currentTimeMillis();
        List<List<Integer>> hisNumList = new ArrayList<>();
        historyNumList.forEach(ssq -> {
            // 第二个|索引
            int secondPipeIndex = ssq.indexOf("|", ssq.indexOf("|") + 1);
            // +索引
            int secondPlusIndex = ssq.indexOf("+", ssq.indexOf("|"));
            // 组合
            String combination = ssq.substring(secondPipeIndex + 1, secondPlusIndex);
            List<Integer> list = Arrays.stream(combination.split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            hisNumList.add(list);
        });

        List<List<Integer>> filterNumList = combinations.stream()
                .filter(combination -> {
                    if (hisNumList.contains(combination)) {
                        System.out.println("历史出现过的组合：" + combination);
                        return false;
                    }
                    return true;
                })
                .collect(Collectors.toList());
        combinations.clear();
        combinations.addAll(filterNumList);
        long endTime = System.currentTimeMillis();
        System.out.println("过滤历史出现过的号码后的所有组合数量：" + filterNumList.size() + " 消耗时间：" + (endTime - startTime) + "ms");
    }

    /**
     * 写出数据
     *
     * @param combinations 全部红球组合
     * @param randomNum 随机几注
     * @param isAppendBlueBall 是否追加蓝球
     */
    private static void waiteData(List<List<Integer>> combinations, int randomNum, boolean isAppendBlueBall) {
        List<String> outputList = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        int blueBall = new Random().nextInt(16) + 1;
        for (List<Integer> combination : combinations) {
            StringBuilder join = new StringBuilder();
            for (int i = 0; i < combination.size(); i++) {
                int num = combination.get(i);
                if(num < 10) {
                    join.append("0").append(num);
                } else {
                    join.append(num);
                }
                if(i != combination.size() - 1) {
                    join.append(",");
                } else {
                    if(isAppendBlueBall) {
                        join.append("+").append(blueBall);
                    }
                }
            }
            outputList.add(join.toString());
        }
        // 清空文件内容
        FileUtil.writeUtf8String("", WRITE_PATH);
        // 写出数据
        FileUtil.appendUtf8Lines(outputList, WRITE_PATH);

        // 对列表进行随机排序
        Collections.shuffle(outputList);
        // 获取前10个元素
        List<String> randomList = outputList.subList(0, randomNum);

        // 清空文件内容
        FileUtil.writeUtf8String("", WRITE_RANDOM_PATH);
        // 写出随机数据
        FileUtil.appendUtf8Lines(randomList, WRITE_RANDOM_PATH);
        long endTime = System.currentTimeMillis();
        System.out.println("写出数据完成！总数量：" + outputList.size() + " 随机数量：" + randomNum +
                " 消耗时间：" + (endTime - startTime) + "ms");
    }

}
